package com.ikingtech.platform.service.system.dept.service.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.department.model.DeptQueryParamDTO;
import com.ikingtech.framework.sdk.enums.system.department.DeptTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.system.dept.entity.DepartmentDO;
import com.ikingtech.platform.service.system.dept.mapper.DeptMapper;

import java.util.*;

/**
 * @author tie yan
 */
public class DeptRepository extends ServiceImpl<DeptMapper, DepartmentDO> {

    public static LambdaQueryWrapper<DepartmentDO> createQueryWrapper(DeptQueryParamDTO queryParam, String tenantCode) {
        return Wrappers.<DepartmentDO>lambdaQuery()
                .eq(Tools.Str.isNotBlank(tenantCode), DepartmentDO::getTenantCode, tenantCode)
                .eq(Tools.Str.isNotBlank(queryParam.getType()), DepartmentDO::getType, queryParam.getType())
                .like(Tools.Str.isNotBlank(queryParam.getName()), DepartmentDO::getName, queryParam.getName())
                .eq(Tools.Str.isNotBlank(queryParam.getManagerId()), DepartmentDO::getManagerId, queryParam.getManagerId())
                .orderByDesc(DepartmentDO::getCreateTime);
    }

    public static LambdaQueryWrapper<DepartmentDO> createQueryWrapper(DeptQueryParamDTO queryParam) {
        return Wrappers.<DepartmentDO>lambdaQuery()
                .in(Tools.Coll.isNotBlank(queryParam.getIds()), DepartmentDO::getId, queryParam.getIds())
                .eq(Tools.Str.isNotBlank(Me.tenantCode()), DepartmentDO::getTenantCode, Me.tenantCode())
                .eq(Tools.Str.isNotBlank(queryParam.getType()), DepartmentDO::getType, queryParam.getType())
                .like(Tools.Str.isNotBlank(queryParam.getName()), DepartmentDO::getName, queryParam.getName())
                .eq(Tools.Str.isNotBlank(queryParam.getManagerId()), DepartmentDO::getManagerId, queryParam.getManagerId())
                .orderByDesc(DepartmentDO::getCreateTime);
    }

    public String findUnityId(String deptId) {
        DepartmentDO entity = this.getById(deptId);
        if (null == entity) {
            throw new FrameworkException("invalidInitiator");
        }
        if (DeptTypeEnum.UNITY.name().equals(entity.getType())) {
            return deptId;
        } else {
            List<String> deptIds = Tools.Str.split(entity.getFullPath(), "@");
            List<DepartmentDO> entities = this.list(Wrappers.<DepartmentDO>lambdaQuery().in(DepartmentDO::getId, deptIds));
            Map<String, DepartmentDO> deptMap = Tools.Coll.convertMap(entities, DepartmentDO::getId);
            return this.getUnitId(deptIds, deptMap);
        }
    }

    public List<String> findUnityIds(List<String> deptIds) {
        return Tools.Coll.convertList(this.findUnitiesById(deptIds), DepartmentDO::getId);
    }

    public List<DepartmentDO> findUnitiesById(List<String> deptIds) {
        if (Tools.Coll.isBlank(deptIds)) {
            return Collections.emptyList();
        }
        return this.findUnities(this.list(Wrappers.<DepartmentDO>lambdaQuery().in(DepartmentDO::getId, deptIds)));
    }

    public List<DepartmentDO> findUnities(List<DepartmentDO> entities) {
        if (Tools.Coll.isBlank(entities)) {
            return Collections.emptyList();
        }
        List<DepartmentDO> allParentEntities = this.list(Wrappers.<DepartmentDO>lambdaQuery().in(DepartmentDO::getId, Tools.Coll.flatMap(entities, entity -> Tools.Str.split(entity.getFullPath(), "@"), Collection::stream)));
        Map<String, DepartmentDO> parentDeptMap = Tools.Coll.convertMap(allParentEntities, DepartmentDO::getId);
        return Tools.Coll.filter(Tools.Coll.convertList(entities, entity -> {
            if (DeptTypeEnum.UNITY.name().equals(entity.getType())) {
                return entity;
            } else {
                return this.getUnit(Tools.Str.split(entity.getFullPath(), "@"), parentDeptMap);
            }
        }), Objects::nonNull);
    }

    public DepartmentDO findUnity(DepartmentDO entity) {
        if (null == entity) {
            return null;
        }
        List<DepartmentDO> allParentEntities = this.list(Wrappers.<DepartmentDO>lambdaQuery().in(DepartmentDO::getId, Tools.Str.split(entity.getFullPath(), "@")));
        Map<String, DepartmentDO> parentDeptMap = Tools.Coll.convertMap(allParentEntities, DepartmentDO::getId);
        return this.getUnit(Tools.Str.split(entity.getFullPath(), "@"), parentDeptMap);
    }

    public String getUnitId(List<String> deptIds, Map<String, DepartmentDO> deptMap) {
        for (int i = deptIds.size() - 2; i >= 0; i--) {
            if (deptMap.containsKey(deptIds.get(i)) && DeptTypeEnum.UNITY.name().equals(deptMap.get(deptIds.get(i)).getType())) {
                return deptIds.get(i);
            }
        }
        return Tools.Str.EMPTY;
    }

    public DepartmentDO getUnit(List<String> deptIds, Map<String, DepartmentDO> deptMap) {
        for (int i = deptIds.size() - 2; i >= 0; i--) {
            if (deptMap.containsKey(deptIds.get(i)) && DeptTypeEnum.UNITY.name().equals(deptMap.get(deptIds.get(i)).getType())) {
                return deptMap.get(deptIds.get(i));
            }
        }
        return null;
    }
}
